﻿using Shared.DJDBDK;
using Shared.Method;
using Shared.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;

namespace ModemSystemNew
{
    /// <summary>
    /// this is class for shared
    /// split the logic and function
    /// the logic only in real forms
    /// </summary>
    public class Common
    {
        //send output message
        public event Action<string> OnOutput;

        public int LocalPort { get; set; }//the start port of localport
        public int LocalOffset { get; private set; } = DateTime.Now.Second;//the offset of localport
        public string LocalIp { get; private set; }
        public string ModemIp { get; private set; }
        public string ModemUser { get; private set; }
        public string ModemPwd { get; private set; }
        public Common(string localIp, int localPort, string modemIp,string user,string pwd)
        {
            if (string.IsNullOrEmpty(localIp)
                || string.IsNullOrEmpty(modemIp)
                || localPort == 0)
            {
                
                return;
            }

            LocalIp = localIp;
            LocalPort = localPort;
            ModemIp = modemIp;
            ModemUser = user;
            ModemPwd = pwd;
        }
        #region get telnet second object


        public YcdTelnetSecond GetTelnetSecond()
        {
            ////初始化telnet
            YcdTelnetSecond tel = null;
            for (int i = 0; i < 5; i++)
            {
                if (LocalOffset >= 800) LocalOffset = 0;
                LocalOffset++;

                tel = YcdTelnetMethod.TelnetModem(LocalIp, ModemIp, LocalPort + LocalOffset, 23, ModemUser, ModemPwd);


                if (tel != null)
                {
                    break;
                }

                Thread.Sleep(4000);
            }

            return tel;
        }

        #endregion

        #region writting information to modem
        /// <summary>
        /// checking firmware version, wheather or not the flash had been mixtrue
        /// </summary>
        /// <param name="deviceData"></param>
        /// <param name="deviceType"></param>
        /// <param name="tel"></param>
        /// <param name="modemType"></param>
        /// <returns></returns>
        public bool CheckInformation(Device_Data deviceData, Device_Type deviceType, YcdTelnetSecond tel, out ModemType modemType)
        {

            //string message = string.Empty;
            modemType = ModemType.DEFAULT;//default like zero, has no meaning

            //固件版本检查
            var writeResult = tel.SendAndRecv("cat /etc/swver", deviceType.BuildTime, out string message);
            if (writeResult == false) { OnOutput?.Invoke(message + "\r校验编译时间失败"); return false; }
            else { OnOutput?.Invoke(message + "\r校验编译时间成功"); }

            //获取固件版本
            if (message.Contains("CMCC") && deviceData.DeviceType.Contains("CMCC"))//移动
            {
                modemType = ModemType.YD_924;
            }
            else if (message.Contains("_CU") && deviceData.DeviceType.Contains("952"))//联通
            {
                modemType = ModemType.LT_952;
            }
            else if (message.Contains("Yueme") && message.Contains("9603C") && deviceData.DeviceType.Contains("926"))//电信9603C
            {
                modemType = ModemType.DX_926;
            }
            else if (message.Contains("Yueme") && message.Contains("9603C") && deviceData.DeviceType.Contains("521"))//电信9603C
            {
                modemType = ModemType.DX_101;
            }
            else if (deviceData.DeviceType.Contains("924"))
            {
                modemType = ModemType.DX_924;
            }
            else
            {
                //AppendRichTextBox("移动联通电信FLASH混料\r固件版本与MAC地址对应的产品品牌不一致\r");
                //SoftShared.SetControl(this, this.labelTestResult, "FLASH混料", Color.Red);
                OnOutput?.Invoke("\r固件与MAC不匹配,FLASH混料");
                return false;
            }

            //inspect wifi message
            bool wifiMsgCheck = Shared.SoftMethod.SoftShared.CheckWifiMsg(tel, out message);

            OnOutput(message + (wifiMsgCheck ? "wifi温补信息检查成功" : "WIFI温补检查失败"));

            return wifiMsgCheck;
        }
        /// <summary>
        /// write something special to optical modem
        /// </summary>
        /// <param name="deviceData"></param>
        /// <param name="deviceType"></param>
        /// <param name="tel"></param>
        /// <param name="modemType"></param>
        /// <returns></returns>
        public  bool WriteInformationSpecial(Device_Data deviceData, Device_Type deviceType, YcdTelnetSecond tel, ModemType modemType)
        {
            if (modemType == ModemType.LT_952 && deviceData.DeviceType.Contains("PT952G"))
            {
                bool writeResult = tel.SendAndRecv("flash set PON_VENDOR_ID YHTC", "=YHTC", out string msg);
                if (writeResult == false) { OnOutput?.Invoke("\r写入PON_VENDOR_ID失败"); return false; }
                else { OnOutput?.Invoke("\r写入PON_VENDOR_ID成功"); }

                writeResult = tel.SendAndRecv("flash set GPON_ONU_MODEL PT952G", "=PT952G", out msg);
                if (writeResult == false) { OnOutput?.Invoke("\r写入GPON_ONU_MODEL失败"); return false; }
                else { OnOutput?.Invoke("\r写入GPON_ONU_MODEL成功"); }
            }

            return true;
        }
        /// <summary>
        /// write information to optical modem
        /// </summary>
        /// <param name="deviceData">data</param>
        /// <param name="deviceType">type</param>
        /// <param name="tel">telnet connect</param>
        /// <returns></returns>
        public  bool WriteInformation(Device_Data deviceData, Device_Type deviceType, YcdTelnetSecond tel)
        {
            if (deviceData == null || deviceType == null || tel == null || !tel.Connected)
            {
                OnOutput?.Invoke("Enter parameters has error in WriteInformation function");
                return false;
            }

            //开启灯光
            tel.SendAndRecv("mpctl led on", "#", out string message);
            OnOutput?.Invoke(message);

            //设备序列号
            bool writeResult = tel.SendAndRecv(string.Format("flash set HW_SERIAL_NO {0}", deviceData.OUI2), "=" + deviceData.OUI2, out  message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写设备序列号失败"); return false; }
            else { OnOutput?.Invoke(message + "写设备序列号成功"); }

            //设备型号
            //ADD_18.3.20，兼容新的类型
            string type = deviceData.DeviceType.Replace(" ", "");
            if (type.Contains("_"))
            {
                type = type.Substring(0, type.IndexOf("_"));
            }

            writeResult = tel.SendAndRecv(string.Format("flash set HW_CWMP_PRODUCTCLASS {0}", type), "=" + type, out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写设备型号失败"); return false; }
            else { OnOutput?.Invoke(message + "写设备型号成功"); }

            //XPON型号
            string ponMode = null;
            if (deviceData.PONType == SharedData.STIA)
            {
                ponMode = "1";
            }
            else
            {
                ponMode = "2";
            }

            writeResult = tel.SendAndRecv(string.Format("flash set PON_MODE {0}", ponMode), "=" + ponMode, out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写PON的型号失败"); return false; }
            else { OnOutput?.Invoke(message + "写PON的型号成功"); }

            //硬件版本
            writeResult = tel.SendAndRecv(string.Format("flash set HW_HWVER {0}", deviceType.HWVersion), "=" + deviceType.HWVersion, out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写设备硬件版本失败"); return false; }
            else { OnOutput?.Invoke(message + "写设备硬件版本成功"); }

            //普通用户密码
            writeResult = tel.SendAndRecv(string.Format("flash set DEFAULT_USER_PASSWORD {0}", deviceData.WedPassword), "=" + deviceData.WedPassword, out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写普通用户密码失败"); return false; }
            else { OnOutput?.Invoke(message + "写普通用户密码成功"); }

            //无线名称
            writeResult = tel.SendAndRecv(string.Format("flash set DEFAULT_WLAN_SSID {0}", deviceData.WIFI_SSID), "=" + deviceData.WIFI_SSID, out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写WIFI名称失败"); return false; }
            else { OnOutput?.Invoke(message + "写WIFI名称成功"); }

            //无线密钥
            writeResult = tel.SendAndRecv(string.Format("flash set DEFAULT_WLAN_WPAKEY {0}", deviceData.WIFI_Password), "=" + deviceData.WIFI_Password, out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写WIFI密码失败"); return false; }
            else { OnOutput?.Invoke(message + "写WIFI密码成功"); }

            //非联通写，itv_ssid不为空要写
            if (string.IsNullOrEmpty(deviceData.ITV_SSID) == false)
            {
                //ITV名称
                writeResult = tel.SendAndRecv(string.Format("flash set HW_SSID2ND {0}", deviceData.ITV_SSID), "=" + deviceData.ITV_SSID, out message);
                if (writeResult == false) { OnOutput?.Invoke(message + "写ITV SSID名称失败"); return false; }
                else { OnOutput?.Invoke(message + "写ITV SSID成功"); }

                //ITV密钥
                writeResult = tel.SendAndRecv(string.Format("flash set HW_WPAKEY2ND {0}", deviceData.ITV_Password), "=" + deviceData.ITV_Password, out message);
                if (writeResult == false) { OnOutput?.Invoke(message + "写ITV 密码失败"); return false; }
                else { OnOutput?.Invoke(message + "写ITV 密码成功"); }
            }

            //光模块型号
            writeResult = tel.SendAndRecv(string.Format("flash set HW_LIGHT_MODEL {0}", deviceData.ProductCode), "=" + deviceData.ProductCode, out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写光模块型号失败"); return false; }
            else { OnOutput?.Invoke(message + "写光模块型号成功"); }

            //光模块序列号
            writeResult = tel.SendAndRecv(string.Format("flash set HW_LIGHT_SN {0}", deviceData.LightModuleSN), "=" + deviceData.LightModuleSN, out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写光模块序列号失败"); return false; }
            else { OnOutput?.Invoke(message + "写光模块序列号成功"); }

            //GPON_SN，只有GPON才写SN号码
            if (deviceData.PONType == "STIA")
            {
                writeResult = tel.SendAndRecv(string.Format("flash set GPON_SN {0}", deviceData.XPON_SN), "=" + deviceData.XPON_SN, out message);
                if (writeResult == false) { OnOutput?.Invoke(message + "写GPON_SN失败"); return false; }
                else { OnOutput?.Invoke(message + "写GPON_SN成功"); }
            }

            //厂商名称
            //string companyName = "youhua";
            writeResult = tel.SendAndRecv(string.Format("flash set HW_CWMP_MANUFACTURER {0}", deviceType.Manufacturer), "=" + deviceType.Manufacturer, out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写厂商名称失败"); return false; }
            else { OnOutput?.Invoke(message + "写厂商名称成功"); }

            //版本校验码key
            writeResult = tel.SendAndRecv(string.Format("flash set HW_CIPHER {0}", deviceData.HW_CIPHER), "=" + deviceData.HW_CIPHER, out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写版本校验码KEY失败"); return false; }
            else { OnOutput?.Invoke(message + "写版本校验码KEY成功"); }

            //软件版本校验码copyright
            writeResult = tel.SendAndRecv(string.Format("flash set HW_COPYRIGHT {0}", deviceType.HWCopyright), "=" + deviceType.HWCopyright, out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "写软件版本校验码copyright失败"); return false; }
            else { OnOutput?.Invoke(message + "写软件版本校验码copyright成功"); }

            //关闭常发光指令
            writeResult = tel.SendAndRecv("flash set USER_FACTORY_BEFORE_RUN 0", "USER_FACTORY_BEFORE_RUN=", out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "关闭常发光失败"); return false; }
            else { OnOutput?.Invoke(message + "关闭常发光成功"); }

            //delete config file
            writeResult = tel.SendAndRecv("rm opt/upt/apps/apps/etc/config/cloudclient", "#", out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "执行删除指令失败"); return false; }
            else { OnOutput?.Invoke(message + "执行删除指成功"); }

            //check up(inspect) the file wheather or not deleted
            writeResult = tel.SendAndRecv(" cat opt/upt/apps/apps/etc/config/cloudclient", "No such file or directory", out message);
            if (writeResult == false) { OnOutput?.Invoke(message + "验证失败"); return false; }
            else { OnOutput?.Invoke(message + "验证成功"); }

            return true;
        }

        public bool WriteMacProvince(Device_Data deviceData,YcdTelnetSecond tel)
        {
            //write mac
            bool writeResult = tel.SendAndRecv($"flash set ELAN_MAC_ADDR {deviceData.MACAddr}", $"={deviceData.MACAddr}", out string message);
            if (writeResult == false) { OnOutput(message + "写MAC失败"); return false; }
            else { OnOutput(message + "写MAC成功"); }

            //写省份信息
            writeResult = tel.SendAndRecv(string.Format("flash set HW_PROVINCE_NAME {0}", deviceData.HW_PROVINCE_NAME), "=" + deviceData.HW_PROVINCE_NAME, out message);
            if (writeResult == false) { OnOutput(message + "写省份信息失败"); return false; }
            else { OnOutput(message + "写省份信息成功"); }

            return true;
        }
        #endregion

        #region check modem web message

        public bool CheckWebMain(string outsideMac, out string webMessage,out string worning)
        {
            webMessage = string.Empty;
            worning = string.Empty;

            Device_Data deviceW = PopCondition(s_stackDeviceData);
            deviceW.Clear();
            deviceW.SetWhere();
            deviceW.MACAddr = outsideMac;
            var selectDevice = Client.MethodWcf.SelectDeviceDataClient(deviceW);
            PushCondition(s_stackDeviceData, deviceW);

            Device_Data device;
            if (selectDevice.result)
            {
                device = selectDevice.value[0];
            }
            else
            {
                return false;
            }

            Device_Type type = GetDeviceType(device.DeviceType, device.HW_PROVINCE_NAME);

            //waitting for 27 seconds
            OnOutput("等待光猫初始化完成,27秒");
            Thread.Sleep(27000);

            if (type.DeviceType.Contains("CMCC"))
            {
                LoginCMCC(LocalIp, ModemIp, type.PROVINCE);
            }

            for(int i = 0; i < 3; ++i)
            {
                webMessage = GetWebinformation(type, LocalIp, ModemIp);
                if (string.IsNullOrEmpty(webMessage)==false) break;
                Thread.Sleep(12000);
            }

            if(string.IsNullOrEmpty(webMessage))
            {
                return false;
            }

            Dictionary<string, string> dictWeb = GetWebDictionary(webMessage);

            if (dictWeb == null) return false;

            return CheckWebInformation(device, dictWeb, type, out worning);
        }

        public bool CheckWebInformation(Device_Data device, Dictionary<string, string> dict, Device_Type type, out string message)
        {
            message = string.Empty;

            if (device == null || dict == null || type == null) { message = "升级固件,解析网页数据失败"; return false; }

            //写入信息到测试结果中

            //youhua_add_180102
            if (dict.TryGetValue("Manufacturer", out string value) && value == type.Manufacturer)
            {
                OnOutput?.Invoke("Manufacturer检查通过");
            }
            else
            {
                OnOutput?.Invoke("Manufacturer检查未通过");
                message = "恢复工厂重走信息检";
                return false;
            }

            //产品型号
            string productType = device.DeviceType.Replace(" ", "");
            if (productType.Contains("_"))
            {
                productType = productType.Substring(0, productType.IndexOf("_"));
            }

            if (dict.TryGetValue("ProductClass", out value) && value == productType)
            {
                OnOutput?.Invoke("ProductClass检查通过");
            }
            else
            {
                OnOutput?.Invoke("ProductClass检查未通过");
                message = "恢复工厂重走信息检";
                return false;
            }

            //硬件版本
            if (dict.TryGetValue("HWVersion", out value) && value == type.HWVersion)
            {
                OnOutput?.Invoke("HWVersion检查通过");
            }
            else
            {
                OnOutput?.Invoke("HWVersion检查未通过");
                message = "恢复工厂重走信息检";
                return false;
            }

            //软件版本
            if (dict.TryGetValue("SWVersion", out value) && value == type.SWVersionInside)
            {
                OnOutput?.Invoke("SWVersion检查通过");
            }
            else
            {
                OnOutput?.Invoke("SWVersion检查未通过");
                message = "固件升级,固件版本检查失败";
                return false;
            }

            //省份信息就检查
            if ((dict.TryGetValue("PROVINCE", out value) == false || string.IsNullOrEmpty(value))
                && string.IsNullOrEmpty(device.HW_PROVINCE_NAME))
            {
                OnOutput?.Invoke("数据库和网页中均无省份信息，未检查");
            }
            else if (dict.TryGetValue("PROVINCE", out value) && value == device.HW_PROVINCE_NAME)
            {
                OnOutput?.Invoke("PROVINCE检查通过");
            }
            else
            {
                OnOutput?.Invoke("PROVINCE检查未通过");
                message = "恢复工厂重走信息检";
                return false;
            }


            //MAC
            if (dict.TryGetValue("MAC", out value) && value == device.MACAddr)
            {
                OnOutput?.Invoke("MAC检查通过");
            }
            else
            {
                OnOutput?.Invoke("MAC检查未通过");
                message = "MAC地址检查失败";
                return false;
            }

            //OUI1
            //兼容9603C版本
            if (dict.TryGetValue("OUI", out value) && value == device.OUI1)
            {
                OnOutput?.Invoke("OUI检查通过");
            }
            else
            {
                OnOutput?.Invoke("OUI检查未通过");
                message = "恢复工厂重走信息检,OUI检查失败";
                return false;
            }
            //}

            //OUI2
            if (dict.TryGetValue("SerialNum", out value) && value == device.OUI2)
            {
                OnOutput?.Invoke("SerialNum检查通过");
            }
            else
            {
                OnOutput?.Invoke("SerialNum检查未通过");
                message = "恢复工厂重走信息检";
                return false;
            }
            //xponMode
            if (dict.TryGetValue("xponMode", out value) && value == type.XPONMode)
            {
                OnOutput?.Invoke("xponMode检查通过");
            }
            else
            {
                OnOutput?.Invoke("xponMode检查未通过");
                message = "检查混料,XPONMode检查失败";
                return false;
            }

            //BOSA类型，1代表GPON，2代表EPON
            string mode = "2";

            //只有xpon为GPON时才检查SN号码，且GPONSN不为空
            if (device.PONType == SharedData.STIA)
            {
                mode = "1";

                //if (device.DeviceType.Contains("_RC") == false && device.DeviceType.Contains("PT926") == false)
                //{
                if (dict.TryGetValue("GPON_SN", out value) && value == device.XPON_SN)
                {
                    OnOutput?.Invoke("GPON_SN检查通过");
                }
                else
                {
                    OnOutput?.Invoke("GPON_SN检查未通过");
                    message = "检查混料，GPON_SN检查未通过";
                    return false;
                }
                //}
            }

            //Mode_只有R方案检查
            if (dict.TryGetValue("Mode", out value) && value == mode)
            {
                OnOutput?.Invoke("Mode检查通过");
            }
            else
            {
                OnOutput?.Invoke("Mode检查未通过");
                message = "检查混料,MODE检查未通过";
                return false;
            }

            //username
            if (dict.TryGetValue("username", out value) && value == device.WedUser)
            {
                OnOutput?.Invoke("username检查通过");
            }
            else
            {
                OnOutput?.Invoke("username检查未通过");
                message = "恢复工厂重走信息检,username未通过";
                return false;
            }
            //password
            if (dict.TryGetValue("web_passwd", out value) && value == device.WedPassword)
            {
                OnOutput?.Invoke("web_passwd检查通过");
            }
            else
            {
                OnOutput?.Invoke("web_passwd检查未通过");
                message = "恢复工厂重走信息检,web_passwd未通过";
                return false;
            }
            //SSID1
            if (dict.TryGetValue("SSID1", out value) && value == device.WIFI_SSID)
            {
                OnOutput?.Invoke("SSID1检查通过");
            }
            else
            {
                OnOutput?.Invoke("SSID1检查未通过");
                message = "恢复工厂重走信息检,username未通过";
                return false;
            }
            //SSID PWD
            if (dict.TryGetValue("WPAPSK1", out value) && value == device.WIFI_Password)
            {
                OnOutput?.Invoke("WPAPSK1检查通过");
            }
            else
            {
                OnOutput?.Invoke("WPAPSK1检查未通过");
                message = "恢复工厂重走信息检,WPAPSK1未通过";
                return false;
            }

            //SSID2检查规则，双向对比
            if (string.IsNullOrEmpty(device.ITV_SSID)
                && (dict.TryGetValue("SSID2", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和光猫上SSID2都为空，不用检查");
            }
            else

                if (dict.TryGetValue("SSID2", out value) && value == device.ITV_SSID && string.IsNullOrEmpty(value) == false)
            {
                OnOutput?.Invoke("SSID2检查通过");
            }
            else
            {
                OnOutput?.Invoke("SSID2检查未通过");
                message = "恢复工厂重走信息检,SSID2未通过";
                return false;
            }

            //SSID 2 PWD
            if (string.IsNullOrEmpty(device.ITV_Password)
                && (dict.TryGetValue("WPAPSK2", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和光猫上WPAPSK2都为空，不用检查");
            }
            else if (dict.TryGetValue("WPAPSK2", out value) && value == device.ITV_Password && string.IsNullOrEmpty(value) == false)
            {
                OnOutput?.Invoke("WPAPSK2检查通过");
            }
            else
            {
                OnOutput?.Invoke("WPAPSK2检查未通过");
                message = "恢复工厂重走信息检,WPAPSK2未通过";
                return false;
            }


            //IP
            if (string.IsNullOrEmpty(type.IP)
                && (dict.TryGetValue("IP", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页均无IP项目，未检查");
            }
            else if (dict.TryGetValue("IP", out value) && value == type.IP)
            {
                OnOutput?.Invoke("IP检查通过");
            }
            else
            {
                OnOutput?.Invoke("IP检查未通过");
                message = "固件升级";
                return false;
            }


            //wanTelnet
            if (dict.TryGetValue("WanTelnet", out value) && value == type.WlanTelnet)
            {
                OnOutput?.Invoke("Wan Telnet检查通过");
            }
            else
            {
                OnOutput?.Invoke("Wan Telnet检查未通过");
                message = "恢复出厂设置";
                return false;
            }

            //LanTelnet
            if (dict.TryGetValue("LanTelnet", out value) && value == type.LanTelnet)
            {
                OnOutput?.Invoke("Lan Telnet检查通过");
            }
            else
            {
                OnOutput?.Invoke("Lan Telnet检查未通过");
                message = "恢复出厂设置";
                return false;
            }

            //checksum，信息校验，R方案需要检查checkSum

            if (dict.TryGetValue("securitycheck", out value) && value == type.securitycheck)
            {
                OnOutput?.Invoke("security check检查通过");
            }
            else
            {
                OnOutput?.Invoke("security check 检查未通过");
                message = "恢复工厂重走信息检,信息安全检查未通过";
                return false;
            }

            //BOB4
            if (string.IsNullOrEmpty(type.BoBtable4check)
                && (dict.TryGetValue("BoBtable4check", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无BoBtable4check，未检查");
            }
            else
                if (dict.TryGetValue("BoBtable4check", out value) && value == type.BoBtable4check)
            {
                OnOutput?.Invoke("BoBtable4check检查通过");
            }
            else
            {
                OnOutput?.Invoke("BoBtable4check 检查未通过");
                message = "恢复工厂重走信息检,信息安全检查未通过";
                return false;
            }

            //BOB5
            if (string.IsNullOrEmpty(type.BoBtable5check)
                && (dict.TryGetValue("BoBtable5check", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无BoBtable5check，未检查");
            }
            else if (dict.TryGetValue("BoBtable5check", out value) && value == type.BoBtable5check)
            {
                OnOutput?.Invoke("BoBtable5check检查通过");
            }
            else
            {
                OnOutput?.Invoke("BoBtable5check 检查未通过");
                message = "恢复工厂重走信息检,信息安全检查未通过";
                return false;
            }

            //PROCESS NAME
            if (string.IsNullOrEmpty(type.ProcessName)
                && (dict.TryGetValue("ProcessName", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无ProcessName，未检查");
            }
            else
                if (dict.TryGetValue("ProcessName", out value) && value.Contains(type.ProcessName))
            {
                OnOutput?.Invoke("ProcessName检查通过");
            }
            else
            {
                OnOutput?.Invoke("ProcessName检查未通过");
                message = "恢复工厂重走信息检,信息安全检查未通过";
                return false;
            }

            if (string.IsNullOrEmpty(type.ProductAgingResult)
                && (dict.TryGetValue("ProductAgingResult", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无ProductAgingResult，未检查");
            }
            else if (dict.TryGetValue("ProductAgingResult", out value) && value == type.ProductAgingResult)
            {
                OnOutput?.Invoke("ProductAgingResult检查通过");
            }
            else
            {
                OnOutput?.Invoke("ProductAgingResult检查未通过");
                message = "重新老化，ProductAgingResult检查未通过";
                return false;
            }


            //WanConnect
            if (string.IsNullOrEmpty(type.WanConnect)
                && (dict.TryGetValue("WanConnect", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无WanConnect，未检查");
            }
            else
                if (dict.TryGetValue("WanConnect", out value) && value == type.WanConnect)
            {
                OnOutput?.Invoke("WanConnect检查通过");
            }
            else
            {
                OnOutput?.Invoke("WanConnect检查未通过");
                message = "固件升级，WanConnect检查未通过";
                return false;
            }


            //PluginNum

            if (string.IsNullOrEmpty(type.PluginNum)
                && (dict.TryGetValue("PluginNum", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无PluginNum，未检查");
            }
            else
                if (dict.TryGetValue("PluginNum", out value) && value == type.PluginNum)
            {
                OnOutput?.Invoke("PluginNum检查通过");
            }
            else
            {
                OnOutput?.Invoke("PluginNum检查未通过");
                message = "插件升级，PluginNum检查未通过";
                return false;
            }


            //pluginName
            if (string.IsNullOrEmpty(type.PluginName)
                && (dict.TryGetValue("PluginName", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无PluginName，未检查");
            }
            else if (dict.TryGetValue("PluginName", out value) && value == type.PluginName)
            {
                OnOutput?.Invoke("PluginName检查通过");
            }
            else if (value.Length == type.PluginName.Length)
            {
                string[] items = value.Split(',');
                foreach (string i in items)
                {
                    if (type.PluginName.Contains(i) == false)
                    {
                        message = "插件升级，PluginName检查未通过";
                        return false;
                    }
                }
                OnOutput?.Invoke("PluginName检查通过");
            }
            else
            {
                OnOutput?.Invoke("PluginName检查未通过");
                message = "插件升级，PluginName检查未通过";
                return false;
            }

            //pluginRun
            if (string.IsNullOrEmpty(type.PluginRun)
                && (dict.TryGetValue("PluginRun", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无PluginRun，未检查");
            }
            else
                if (dict.TryGetValue("PluginRun", out value) && value == type.PluginRun)
            {
                OnOutput?.Invoke("PluginRun检查通过");
            }
            else
            {
                OnOutput?.Invoke("PluginRun检查未通过");
                message = "插件升级，PluginRun检查未通过";
                return false;
            }

            //Framework1
            if (string.IsNullOrEmpty(type.FrameWork1)
                && (dict.TryGetValue("Framework1", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无Framework1，未检查");
            }
            else
                if (dict.TryGetValue("Framework1", out value) && value == type.FrameWork1)
            {
                OnOutput?.Invoke("Framework1检查通过");
            }
            else
            {
                OnOutput?.Invoke("Framework1检查未通过");
                message = "插件升级，Framework1检查未通过";
                return false;
            }

            //Framework2
            if (string.IsNullOrEmpty(type.FrameWork2)
                && (dict.TryGetValue("Framework2", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无Framework2，未检查");
            }
            else
                if (dict.TryGetValue("Framework2", out value) && value == type.FrameWork2)
            {
                OnOutput?.Invoke("Framework2检查通过");
            }
            else
            {
                OnOutput?.Invoke("Framework2检查未通过");
                message = "插件升级,Framework2检查未通过";
                return false;
            }

            //APPS
            if (string.IsNullOrEmpty(type.APPS)
                && (dict.TryGetValue("APPS", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无APPS，未检查");
            }
            else
                if (dict.TryGetValue("APPS", out value) && value == type.APPS)
            {
                OnOutput?.Invoke("APPS检查通过");
            }
            else
            {
                OnOutput?.Invoke("APPS检查未通过");
                message = "插件升级，APPS检查未通过";
                return false;
            }


            //Framework(active)
            if (string.IsNullOrEmpty(type.FrameworkActive)
              && (dict.TryGetValue("Framework(active)", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无Framework(active)，未检查");
            }
            else
              if (dict.TryGetValue("Framework(active)", out value) && value == type.FrameworkActive)
            {
                OnOutput?.Invoke("Framework (active)检查通过");
            }
            else
            {
                OnOutput?.Invoke("Framework (active)检查未通过");
                message = "插件升级，Framework (active)检查未通过";
                return false;
            }


            //URL
            if (string.IsNullOrEmpty(type.URL)
                && (dict.TryGetValue("URL", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无URL，未检查");
            }
            else
                if (dict.TryGetValue("URL", out value) && value == type.URL)
            {
                OnOutput?.Invoke("URL检查通过");
            }
            else
            {
                OnOutput?.Invoke("URL检查未通过");
                message = "固件升级，URL检查未通过";
                return false;
            }

            //RelativeURL
            if (string.IsNullOrEmpty(type.RelativeURL)
                && (dict.TryGetValue("RelativeURL", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无RelativeURL，未检查");
            }
            else
                if (dict.TryGetValue("RelativeURL", out value) && value == type.RelativeURL)
            {
                OnOutput?.Invoke("Relative URL检查通过");
            }
            else
            {
                OnOutput?.Invoke("Relative URL检查未通过");
                message = "固件升级，Relative URL检查未通过";
                return false;
            }

            //LastChangedRev
            if (string.IsNullOrEmpty(type.SWVersion)
                && (dict.TryGetValue("LastChangedRev", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无LastChangedRev，未检查");
            }
            else
                if (dict.TryGetValue("LastChangedRev", out value) && value == type.SWVersion)
            {
                OnOutput?.Invoke("Last Changed Rev检查通过");
            }
            else
            {
                OnOutput?.Invoke("Last Changed Rev检查未通过");
                message = "固件升级，Last Changed Rev检查未通过";
                return false;
            }

            //LastChangedData
            if (string.IsNullOrEmpty(type.LastChangedDate)
                && (dict.TryGetValue("LastChangedDate", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无LastChangedDate，未检查");
            }
            else
                if (dict.TryGetValue("LastChangedDate", out value) && value == type.LastChangedDate)
            {
                OnOutput?.Invoke("Last Changed Date检查通过");
            }
            else
            {
                OnOutput?.Invoke("Last Changed Date检查未通过");
                message = "固件升级，Last Changed Date检查未通过";
                return false;
            }

            //Compile Time
            if (string.IsNullOrEmpty(type.BuildTime)
                && (dict.TryGetValue("CompileTime", out value) == false || string.IsNullOrEmpty(value)))
            {
                OnOutput?.Invoke("数据库和网页上均无CompileTime，未检查");
            }
            else
                if (dict.TryGetValue("CompileTime", out value) && value == type.BuildTime.Replace(" ", "").Replace(":", ""))
            {
                OnOutput?.Invoke("Compile Time检查通过");
            }
            else
            {
                OnOutput?.Invoke("Compile Time检查未通过");
                message = "固件升级，Compile Time检查未通过";
                return false;
            }

            message = "检查通过";

            return true;
        }

        /// <summary>
        /// 获取网页数据
        /// </summary>
        /// <returns></returns>
        public string GetWebinformation(Device_Type type, string localIp,string modemIp)
        {
            //使用新的类YcdTelnetClass
            if (LocalOffset >= 800) LocalOffset = 0;
            LocalOffset++;

            HttpArgs httpArgs = new HttpArgs
            {
                Url = "/cgi-bin/cgic_systeminfo.cgi",
            };

            string webKey;
            if (type.DeviceType.Contains("PT952"))
            {
                httpArgs.Port = 80;
                httpArgs.Host = "192.168.1.1:80";
                webKey = type.ProcessName;
            }
            else if (type.DeviceType.Contains("CMCC"))
            {
                httpArgs.Port = 80;
                httpArgs.Host = "192.168.1.1:80";
                webKey = type.PluginRun;
            }
            else
            {
                httpArgs.Port = 8080;
                httpArgs.Host = "192.168.1.1:8080";
                webKey = type.PluginRun;
            }

            //使用新的方法获取网页数据
            bool hasKey = HttpBaseClass.GetHttpMsg(localIp,LocalPort+LocalOffset, modemIp, httpArgs.Port, httpArgs, webKey, out string modemMsg);

            Thread.Sleep(300);

            if (hasKey == false) return string.Empty;//the false flag

            return modemMsg;
        }

        /// <summary>
        /// 将光猫数据从字符串转换为键值对
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public Dictionary<string, string> GetWebDictionary(string msg)
        {
            if (string.IsNullOrEmpty(msg)) return null;

            var dict = new Dictionary<string, string>();
            //去除信息中的所有空格
            msg = msg.Replace(" ", "");
            //去掉所有横杠
            //msg = msg.Replace("-", "");

            //将信息按照换行符分割，并去除掉头尾的空白字符
            var listMsg = msg.Split('\n');

            //继续将信息按照冒号分割成键值对
            for (int i = 0; i < listMsg.Length; i++)
            {
                var temp = listMsg[i].Split(':');

                //获取key和value
                string key = null;
                string value = null;

                if (temp.Length == 2)
                {
                    key = temp[0].Trim();
                    value = temp[1].Trim();
                }
                else if (temp.Length > 2)
                {
                    key = temp[0].Trim();

                    for (int j = 1; j < temp.Length; j++)
                    {
                        value += temp[j].Trim();
                    }
                }

                if (key == null) continue;

                //增加键值对
                if (dict.ContainsKey(key) == false)
                {
                    dict.Add(key, value);
                }
                else
                {
                    dict.TryGetValue(key, out string keyValue);

                    keyValue += "," + value;
                    dict.Remove(key);
                    dict.Add(key, keyValue);
                }
            }
            return dict;
        }


        public void LoginCMCC( string localip, string modemIp, string province)
        {
            HttpArgs args = new HttpArgs()
            {
                Host = "192.168.1.1",
                Url = "/admin/login.asp",
                Port = 80
            };

            if (LocalOffset >= 800) LocalOffset = 0;
            LocalOffset++;

            HttpBaseClass.GetHttpMsg(localip, LocalPort+LocalPort, modemIp, args.Port, args, "OK", out string oMsg, HttpBaseClass.HttpMethod.GET);

            string pattern = @"csrfmiddlewaretoken.+/>";
            var match = Regex.Match(oMsg, pattern);
            if (match.Success == false) return;
            string csrftoken = match.Value.Substring(match.Value.IndexOf('=') + 2, 32);

            pattern = @"csrftoken.+/>";
            var match2 = Regex.Match(oMsg, pattern);
            if (match2.Success == false) return;
            string wareToken = match2.Value.Substring(match2.Value.IndexOf('=') + 2, 32);

            string user = "CMCCAdmin";
            string pwd = "aDm8H%MdA";

            if (province.Contains("GX"))
            {
                user = "admin";
                pwd = "Cmcc10086#";
            }

            args.Url = "/boaform/admin/formLogin";
            args.Host = "192.168.1.1";
            args.Body = string.Format("username2=user&psd2=&username1={0}&psd1={1}&csrfmiddlewaretoken={2}&username={0}&psd={1}&csrftoken={3}"
                , user
                , pwd
                , wareToken
                , csrftoken);

            if (LocalOffset >= 800) LocalOffset = 0;
            LocalOffset++;

            HttpBaseClass.GetHttpMsg(localip, LocalPort+LocalOffset, modemIp, args.Port, args, "OK", out oMsg, HttpBaseClass.HttpMethod.POST);

        }

        #endregion

        //public static event Action<int, string> OnStaticOutput;

        #region Stack
        private static T PopCondition<T>(Stack<T> stack) where T : new()
        {
            //return new T();
            if (stack == null) return default(T);

            if (stack.Count == 0)
            {
                return new T();
            }

            lock (stack)
            {
                return stack.Pop();
            }
        }

        private static void PushCondition<T>(Stack<T> stack, T item) where T : new()
        {
            if (stack == null) return;


            lock (stack)
            {
                stack.Push(item);
            }
        }

        #endregion

        #region get device type

        private static List<Device_Type> s_listDeviceType = new List<Device_Type>();
        public static Device_Type GetDeviceType(string type, string province)
        {
            if (s_listDeviceType.Count == 0)
            {
                Device_Type typeW = new Device_Type();
                var selectType = Client.MethodWcf.SelectDeviceTypeClient(typeW);
                if (selectType.result)
                {
                    s_listDeviceType = selectType.value;
                }
                else
                {
                    return null;
                }
            }

            var device = (from t in s_listDeviceType
                          where t.DeviceType == type && t.PROVINCE == province
                          select t).FirstOrDefault();

            return device;
        }

        #endregion

        #region binding inside and outside MAC or unbinding

        //private static PRODUCT s_productW = new PRODUCT();
        //private static PROCESS s_processW = new PROCESS();

        private static readonly Stack<PRODUCT> s_stackProduct = new Stack<PRODUCT>();
        private static readonly Stack<PROCESS> s_stackProcess = new Stack<PROCESS>();
        private static readonly Stack<Device_Data> s_stackDeviceData = new Stack<Device_Data>();

        public static bool BindingMac(string insideMac,string outsideMac,out Device_Data outDevice,out string message)
        {
            outDevice = null;
            message = string.Empty;

            if (string.IsNullOrEmpty(insideMac) 
                || string.IsNullOrEmpty(outsideMac))
            {
                message = "传入的光猫MAC或扫描MAC为空";
                return false;
            }

            //what states can be bind?
            //only inside mac is a factory mac, out side mac is a user model mac and all of them did not bind can be binding here.

            //check mac
            //insideMac = insideMac.ToUpper();
            //outsideMac = outsideMac.ToUpper();

            if(insideMac.Contains("FCDF")==false 
                && insideMac.Contains("FCDE")==false)
            {
                message = "光猫MAC不是内部MAC";
                return false;
            }

            //check bind
            PRODUCT productW = PopCondition(s_stackProduct);

            productW.Clear();
            productW.SetWhere($"(YCD_MAC='{insideMac}' AND MAC IS NOT NULL AND MAC<>'') OR MAC='{outsideMac}'");
            var selectCountProduct = Client.MethodWcf.SelectProductCountClient(productW);

            PushCondition(s_stackProduct, productW);
            if(selectCountProduct.message!="0")
            {
                message = "光猫MAC或扫描MAC已绑定，不能再次绑定";
                return false;
            }

            //get outside's Device_Data and inspect the pontype

            string sql = $@"
UPDATE Modem.dbo.Device_Data
SET LightModuleSN = (
	SELECT
		LightModuleSN
	FROM
		Modem.dbo.YCD_DEVICE
	WHERE
		YCD_MAC = '{insideMac}'
)
WHERE
	MACAddr = '{outsideMac}'
AND PONType = (
	SELECT
		PONType
	FROM
		Modem.dbo.YCD_DEVICE
	WHERE
		YCD_MAC = '{insideMac}'
)
";

            var updateSql = Client.MethodWcf.ExecuteSQLClient(sql);

            if (updateSql <= 0)
            {
                message = "更新Device_Data失败，原因可能是PON类型不一致";
                return false;
            }

            var deviceW = PopCondition(s_stackDeviceData);

            deviceW.Clear();
            deviceW.SetWhere();
            deviceW.MACAddr = outsideMac;
            var selectDevice = Client.MethodWcf.SelectDeviceDataClient(deviceW);

            PushCondition(s_stackDeviceData, deviceW);

            if (selectDevice.result)
            {
                outDevice = selectDevice.value[0];
            }
            else
            {
                message = "查询Device_Data失败";
                return false;
            }

            //cancel station limit
            //binding inside mac and outside mac

            productW = PopCondition(s_stackProduct);

            productW.Clear();
            productW.SetWhere();
            productW.YCD_MAC = insideMac;
            productW.SetUpdate();
            productW.MAC = outsideMac;

            var update = Client.MethodWcf.UpdateProductClient(productW);

            PushCondition(s_stackProduct, productW);

            if(update.message!="0")
            {
                return true;
            }

            message = $"update {update.message} items of database table";
            return false;
        }

        public static bool Unbinding(string outsideMac,string insideMac=null)
        {
            if (string.IsNullOrEmpty(outsideMac)) return false;

            PRODUCT productW = PopCondition(s_stackProduct);
            productW.Clear();

            string where = $"MAC='{outsideMac}'{(string.IsNullOrEmpty(insideMac) ? string.Empty : $" AND YCD_MAC='{insideMac}'")}";

            productW.SetWhere(where);
            productW.SetUpdate();
            productW.MAC = null;

            var update = Client.MethodWcf.UpdateProductClient(productW);

            PushCondition(s_stackProduct, productW);
            if(update.result&&update.message!="0")
            {
                return true;
            }

            return false;
        }

        #endregion

        #region going to what step

        public static WORK_STEP CheckStep(string insideMac, string outsideMac,out string message)
        {
            message = string.Empty;
            //inspect inside mac and out side mac
            //insideMac = insideMac.Trim().ToUpper();
            //outsideMac = outsideMac.Trim().ToUpper();

            if (insideMac != outsideMac
                && (insideMac.Contains(SharedData.YCD_MAC_EPON_START) || insideMac.Contains(SharedData.YCD_MAC_GPON_START)))
            {
                return WORK_STEP.WRITE_MSG;
            }

            if (insideMac != outsideMac)
            {
                message = $"内外MAC不一致，内部为{insideMac}，外部为{outsideMac}";
                return WORK_STEP.NO_WHERE;
            }

            //inside and outside mac is identical
            //first condition --- mac bind
            PRODUCT productW = PopCondition(s_stackProduct);

            productW.Clear();
            productW.SetWhere();
            productW.MAC = insideMac;

            var selectCount = Client.MethodWcf.SelectProductCountClient(productW);

            PushCondition(s_stackProduct, productW);

            if(selectCount.result==false
                || selectCount.message!="1")
            {
                message = "MAC未绑定，不能进行出厂信息检查";
                return WORK_STEP.NO_WHERE;
            }

            //second conditon --- the TEST_RESULT_ONE is 1 or the TEST_RESULT_TWO is existence on the last row of table process
            PROCESS processW = PopCondition(s_stackProcess);
            processW.Clear();
            processW.SetWhere(
                $"(TEST_RESULT_ONE={SharedData.TEST_RESULT_PART_TRUE} OR TEST_RESULT_TWO IS NOT NULL) AND ID =(SELECT TOP 1 ID FROM PROCESS WHERE MAC='{outsideMac}' ORDER BY ID DESC)"
                );

            selectCount = Client.MethodWcf.SelectProcessCountClient(processW);

            PushCondition(s_stackProcess, processW);

            if(selectCount.result==false || selectCount.message!="1")
            {
                return WORK_STEP.NO_WHERE;
            }

            //outside and inside mac is bind. writting/testing had done.

            return WORK_STEP.CHECK_WEB;
        }

        #endregion

        #region test function of optical modem

        //wifi/reset/led/wps button

        public static bool ButtonTesting(YcdTelnetSecond tel, string key, /*string tips,*/out string message)
        {
            message = string.Empty;
            //判断tel是否连接着
            if (tel == null || tel.Connected == false)
            {
                //AppendRichTextBox("按键测试失败，传入参数错误");
                message = "按键测试失败，传入参数错误";
                return false;
            }

            bool ret = false;

            //重试30次
            for (int i = 0; i < 30; i++)
            {
                ret = tel.SendAndRecv(null, key, out string msg, 1800);

                //AppendRichTextBox(msg);
                message += msg;

                if (ret) break;
            }

            if (ret) message += "测试成功";
            else message += "测试失败";

            return ret;
        }

        //voice test

        //语音测试，返回true or false

        public static bool VoiceTesting(int voiceNum, YcdTelnetSecond tel, string keyWord ,out string message)
        {
            message = string.Empty;

            //判断参数是否正确
            if (voiceNum > 7 || voiceNum < 0 || tel == null || tel.Connected == false)
            {
                //AppendRichTextBox("语音测试失败，传入参数错误");
                message = "语音测试失败，传入参数错误";
                return false;
            }
            //挂机
            VoiceBaseClass.ResetChannel(voiceNum);

            //bool recvResult = TelnetSendAndRecv(tel, "voipmp", keyWord);//18.1.25修改，兼容R方案1.23日版本
            bool recvResult = tel.SendAndRecv("voipmp", keyWord, out string outMsg, 5000);

            //AppendRichTextBox(outMsg);
            if (outMsg.Contains("getHookState"))
            {
                //AppendRichTextBox("语音回显异常，不能测试语音功能");
                message = "语音回显异常，不能测试语音功能";
                return false;
            }

            message += outMsg;

            if (tel.SendAndRecv(string.Empty, "getHookState", out outMsg, 2000))
            {
                //AppendRichTextBox(outMsg + "\r\n语音回显异常，不能测试语音功能");
                message += "\r\n语音回显异常，不能测试语音功能";
                return false;
            }

            if (recvResult == false)
            {
                //AppendRichTextBox("未能开启语音测试功能");
                message += "未能开启语音测试功能";
                return false;
            }

            //开始测试语音
            recvResult = VoiceBaseClass.DialNum(voiceNum, "*159#", out outMsg);

            message += outMsg;

            tel.SendAndRecv(null, "#", out outMsg);

            message += outMsg;

            return recvResult;
        }

        //USB测试
        public static bool UsbTest(YcdTelnetSecond tel, out string message)
        {
            message = string.Empty;
            //判断tel是否连接着
            if (tel == null || tel.Connected == false)
            {
                message += "USB测试失败，传入参数错误";
                return false;
            }

            bool ret = false;


            //重试30次
            for (int i = 0; i < 6; i++)
            {
                ret = tel.SendAndRecv("usbmp", "success", out string msg);
                message += msg;
                if (ret) break;
            }

            if (ret) message += "USB测试成功";
            else
            {
                message += "USB测试失败";
                return false;
            }

            return true;
        }

        #endregion

        #region reset to user model

        /// <summary>
        /// 重置光猫
        /// </summary>
        /// <param name="tel"></param>
        /// <param name="deviceType"></param>
        /// <param name="message"></param>
        public static bool ResetModem(YcdTelnetSecond tel, ModemType deviceType, out string message)
        {
            System.Threading.Thread.Sleep(1000);

            message = string.Empty;

            string msg;
            bool result = false;

            if (deviceType == ModemType.DX_924)
            {
                result = tel.SendAndRecv("flash default cs\r\n", "reboot", out msg, 15000);
            }
            else
            {
                result = tel.SendAndRecv("mp_default\r\n", "reboot", out msg, 15000);
            }

            //AppendRichTextBox(msg);
            message += msg;


            if (result == false)
            {
                message += "恢复出厂设置失败";
                return false;
            }

            //message += msg;

            if (deviceType != ModemType.YD_924)
            {
                tel.Send("reboot -f");

                message += "#reboot -f\r\n重置光猫开始……";

                Thread.Sleep(6000);
            }

            return true;
        }

        #endregion

        #region writting log

        //Write log message, first part write/test function, second reset user model , third inspect web information
        public static bool InsertPartFinishProcess(string mac, bool testResult, WORK_STEP step)
        {
            if (testResult == false && step == WORK_STEP.WRITE_MSG) return false;

            PROCESS processI = PopCondition(s_stackProcess);
            processI.Clear();
            processI.SetUpdate();

            processI.MAC = mac;
            processI.FLOW_ID = 117;


            if (step == WORK_STEP.WRITE_MSG)
            {
                processI.WORKER_ID = 66666666;
                processI.WORKER_NAME = "语音信息检查";
                processI.LINE_ID = 6666;
                processI.NODE_ID = 66666;
                processI.STATION_ID = 6666;
                processI.TEST_RESULT_ONE = SharedData.TEST_RESULT_PART_TRUE;
            }
            else if (step == WORK_STEP.CHECK_WEB)
            {
                processI.WORKER_ID = 99999999;
                processI.WORKER_NAME = "网页检查";
                processI.LINE_ID = 9999;
                processI.NODE_ID = 99999;
                processI.STATION_ID = 9999;
                processI.TEST_RESULT_TWO = testResult ? SharedData.TEST_RESULT_PART_TRUE : SharedData.TEST_RESULT_PART_FALSE;
            }

            processI.TEST_RESULT = SharedData.TEST_RESULT_TRUE;
            processI.START_TIME = DateTime.Now;
            processI.END_TIME = DateTime.Now;

            var insert = Client.MethodWcf.InsertProcessClient(processI);

            PushCondition(s_stackProcess, processI);

            if (insert.result && insert.message == "1")
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        #endregion

        #region scan mac from optical modem

        private static readonly List<System.IO.Ports.SerialPort> s_serialPorts = new List<System.IO.Ports.SerialPort>();

#if false

        /// <summary>
        /// first parameter is serialName,second is sign
        /// </summary>
        public static event Action<string, string> OnScanSign;
        public static Stack<string> s_stackSerial = new Stack<string>();

        //private static Task s_task = null;

        private static bool s_boolTaskRun = false;

        public static void RunScan()
        {
            if (s_boolTaskRun) return;

            s_boolTaskRun = true;

            Task.Run(() =>
              {
                  string serialPortName = string.Empty;
                  string sign = string.Empty;

                  while (s_boolTaskRun)
                  {
                      System.Threading.Thread.Sleep(1000);

                      if (s_stackSerial.Count == 0) continue;

                      serialPortName = s_stackSerial.Pop();

                      sign = ScanSign(serialPortName);

                      //发送指令
                      OnScanSign(serialPortName, sign);
                  }
              });
        }

        public static void AddScanTask(string serialPortName)
        {
            lock (s_stackSerial)
                s_stackSerial.Push(serialPortName);
        }
#endif
        public static string ScanSign(string serialPortName)
        {
            //test
            //return "2C557C7C630C";

            System.IO.Ports.SerialPort serial;

            lock (s_serialPorts)
            {
                serial = s_serialPorts.Where(a => a.PortName == serialPortName).FirstOrDefault();
                if (serial == null) serial = PortBaseClass.GetNewSerialPort(9600, serialPortName, 8, out string msg);
                if (serial == null) return string.Empty;
                s_serialPorts.Add(serial);
            }

            string signNumber = PortBaseClass.ScanControl(serial, serialPortName,SharedData. SCAN2, SharedData.SCAN2_ACK);
            if (string.IsNullOrEmpty(signNumber))
                signNumber = PortBaseClass.ScanControl(serial, serialPortName, SharedData.SCAN2, SharedData.SCAN2_ACK);

            return signNumber;
        }

        public static void ReleaseSerial()
        {
            //s_boolTaskRun = false;

            if (s_serialPorts.Count == 0) return;

            for(int i = 0; i < s_serialPorts.Count; i++)
            {
                s_serialPorts[i].Close();
                s_serialPorts[i].Dispose();
            }

            s_serialPorts.Clear();   
        }

        //open and close power of optical modem
        public static bool PowerOffAndOn(int switchNum,string serialPortName)
        {
            System.IO.Ports.SerialPort serial;

            lock (s_serialPorts)
            {
                serial = s_serialPorts.Where(a => a.PortName == serialPortName).FirstOrDefault();
                if (serial == null) serial = PortBaseClass.GetNewSerialPort(9600, serialPortName, 8, out string msg);
                if (serial == null) return false;
                s_serialPorts.Add(serial);
            }

            return PortBaseClass.PowerOffAndOn(switchNum, serial);
        }

        #endregion

        #region using arp to get mac from optical modem , get ycd telnet object
        /// <summary>
        /// waitting 45 seconds
        /// </summary>
        /// <param name="localIp">local ipaddress</param>
        /// <param name="modemIp">modem address</param>
        /// <returns></returns>
        public static string GetModemMacFromArp(string localIp, string modemIp)
        {
            //PING光猫
            int pingOkTimes = 0;

            for (int i = 0; i < 120; i++)
            {
                if (PingBaseClass.PingTest(localIp, modemIp))
                {
                    pingOkTimes++;
                    if (pingOkTimes >= 4)
                        break;
                }
                else
                {
                    pingOkTimes = 0;
                }

                Thread.Sleep(200);
            }

            string mac = string.Empty;

            for (int i = 0; i < 3 && pingOkTimes >= 4; i++)
            {
                mac = ArpBaseClass.GetMacFromIp(localIp, modemIp);
                if (string.IsNullOrEmpty(mac))
                {
                    Thread.Sleep(2000);
                }
                else break;
            }

            return mac;
        }

        #endregion
    }
}
